﻿
    using System;
    using System.Reflection;


namespace DailyFx.UI
{

	public interface IUIControl : IUIDisplayText, IUIStatus, IUIGuardClose, INotifyPropertyChangedEx, IDisposable
	{
		// Empty ??
	}

    /// <summary>
    ///  
    /// </summary>
    public class UIControl : ViewAware, IUIControl, IUIChild 
	{
        static readonly ILog Log = LogManager.GetLog( typeof( UIControl) );

		/// <summary>
		///		indicates whether this control is loaded
		/// </summary>
		bool _isLoaded;

       /// <summary>
		///		indicates if this control is enabled .
		/// </summary>
		private bool _isEnabled;

        /// <summary>
		///		the parent conductor of this control .
		/// </summary>
		object parent;

		/// <summary>
		///		the text of this control to display .
		/// </summary>
        string _text;



        /// <summary>
        ///   c'tor
        /// </summary>
        public UIControl ( string text = null ) 
		{
            this._text = text ?? this.GetType().FullName;
        }

#if DEBUG
        /// <summary>
        ///		Useful for ensuring that UIElement objects are properly garbage collected.
        /// </summary>
        ~UIControl ()
        {

        }
#endif

		/// <summary>
		///   Indicates whether or not this instance is currently active.
		/// </summary>
		public bool IsEnabled
		{
			get
			{
				return this._isEnabled;
			}
			private set
			{
				this._isEnabled = value;
				this.RaisePropertyChanged("IsEnabled");
			}
		}

		/// <summary>
		///   Indicates whether or not this instance is currently initialized.
		/// </summary>
		public bool IsLoaded
		{
			get
			{
				return this._isLoaded;
			}
			private set
			{
				this._isLoaded = value;
				this.RaisePropertyChanged("IsLoaded");
			}
		}

        /// <summary>
        ///   Gets or Sets the Parent <see cref = "IUIConductor" />
        /// </summary>
        public object Parent 
		{
            get 
			{ 
				return this.parent; 
			}
            set 
			{
                this.parent = value;
                RaisePropertyChanged( "Parent" );
            }
        }

		/// <summary>
		///   Gets or Sets the Key Text 
		/// </summary>
		public string KeyText
		{
			get
			{
				return this._text;
			}
			set
			{
				this._text = value;
				this.RaisePropertyChanged("KeyText");
				// this.RaisePropertyChanged("DisplayText");

			}
		}

        /// <summary>
        ///   Gets or Sets the Display Text 
        /// </summary>
        public string DisplayText 
		{
            get 
			{ 
				return this._text; 
			}
            set 
			{
                this._text = value;
                this.RaisePropertyChanged("DisplayText");
            }
        }



		/// <summary>
		///   Raised after enabling occurs .
		/// </summary>
		public event EventHandler<UIEnabledEventArgs> Enabled = delegate { };

		/// <summary>
		///   Raised before disabling .
		/// </summary>
		public event EventHandler<UIDisabledEventArgs> AttemptingDisabled = delegate { };

		/// <summary>
		///   Raised after disabled .
		/// </summary>
		public event EventHandler<UIDisabledEventArgs> Disabled = delegate { };



        void IUIStatus.SetEnabled ()
		{
            if ( this.IsEnabled )
			{
                return;
            }

            var loaded = false;

            if (! this.IsLoaded )
			{
                this.IsLoaded = loaded = true;
				// notify to load this control  .
                this.OnLoaded ();
            }

            this.IsEnabled = true;
            Log.Info ( "Enabling {0}.", this );
            
			// handle when enabled .
			this.OnEnabled ();

			// notify this control enabled .
            this.Enabled(this, new UIEnabledEventArgs { WasLoaded = loaded });
        }

		void IUIStatus.SetDisabled ( bool close )
		{
			if ( this.IsEnabled || ( this.IsLoaded && close) )
			{
				// notify attempt to disabling .
				this.AttemptingDisabled ( this, new UIDisabledEventArgs { WasClosed = close });

				this.IsEnabled = false;
				Log.Info( "Disabling {0}.", this );
				
				// handle when disabling 
				this.OnDisabled ( close );

				this.Disabled ( this, new UIDisabledEventArgs { WasClosed = close });

				if ( close )
				{
					// release the cached views .
					this.Views.Clear() ;
					Log.Info("Closed {0}.", this );
				}
			}
		}

        /// <summary>
        ///   Called when enabling .
        /// </summary>
        protected virtual void OnEnabled () 
		{ 
		}

        /// <summary>
        ///   Called when deactivating.
        /// </summary>
        protected virtual void OnDisabled(bool close) 
		{
		}


		/// <summary>
		///   Called when loading.
		/// </summary>
		protected virtual void OnLoaded ()
		{
		}


        /// <summary>
        ///   Called to check whether or not this control can be closed .
        /// </summary>
        public virtual void CanClose( Action<bool> callback ) 
		{
            callback(true);
        }

        System.Action GetViewCloseAction ( bool? dialogResult)
		{
           

            foreach (var contextualView in Views.Values) {
                var viewType = contextualView.GetType();
#if WinRT
                var closeMethod = viewType.GetRuntimeMethod("Close", new Type[0]);
#else
                var closeMethod = viewType.GetMethod("Close");
#endif
                if(closeMethod != null)
                    return () => {
#if !SILVERLIGHT && !WinRT
                        var isClosed = false;
                        if(dialogResult != null) {
                            var resultProperty = contextualView.GetType().GetProperty("DialogResult");
                            if (resultProperty != null) {
                                resultProperty.SetValue(contextualView, dialogResult, null);
                                isClosed = true;
                            }
                        }

                        if (!isClosed) {
                            closeMethod.Invoke(contextualView, null);
                        }
#else
                        closeMethod.Invoke(contextualView, null);
#endif
                    };

#if WinRT
                var isOpenProperty = viewType.GetRuntimeProperty("IsOpen");
#else
                var isOpenProperty = viewType.GetProperty("IsOpen");
#endif
                if (isOpenProperty != null) {
                    return () => isOpenProperty.SetValue(contextualView, false, null);
                }
            }

            return () => Log.Info("TryClose requires a parent IConductor or a view with a Close method or IsOpen property.");
        }

        /// <summary>
        ///   Tries to close this instance by asking its Parent to initiate shutdown or by asking its corresponding view to close.
        /// </summary>
        public virtual void TryClose() {
            GetViewCloseAction(null).OnUIThread();
        }

#if !SILVERLIGHT
        /// <summary>
        /// Closes this instance by asking its Parent to initiate shutdown or by asking it's corresponding view to close.
        /// This overload also provides an opportunity to pass a dialog result to it's corresponding view.
        /// </summary>
        /// <param name="dialogResult">The dialog result.</param>
        public virtual void TryClose ( bool? dialogResult ) 
		{
			var conductor = Parent as IUIConductor;
			if (conductor != null)
			{
				Execution.OnUIThread ( () => conductor.DisableChild (this, true ) );
				return;
			}

			foreach ( var view in Views.Values )
			{
				var viewType = view.GetType();
#if WinRT
                var closeMethod = viewType.GetRuntimeMethod( "Close", new Type[0] );
#else
				var closeMethod = viewType.GetMethod( "Close" );
#endif
				if ( closeMethod != null )
				{
				
					Execution.OnUIThread ( () =>
					{
#if !SILVERLIGHT && !WinRT
						var isClosed = false;
						if ( dialogResult != null )
						{
							var result = view.GetType().GetProperty( "DialogResult" );
							if (result != null)
							{
								result.SetValue( view, dialogResult, null );
								isClosed = true;
							}
						}

						if (!isClosed)
						{
							closeMethod.Invoke(view, null);
						}
#else
                        closeMethod.Invoke( view, null );
#endif
					} );

					// Ok, called the "Close" method of FrameworkElement.
					return;
				}
#if WinRT
                var isOpen = viewType.GetRuntimeProperty( "IsOpen" );
#else
				var isOpen = viewType.GetProperty( "IsOpen" );
#endif
				if ( isOpen != null )
				{
					Execution.OnUIThread ( () => isOpen.SetValue(view, false, null) );
					return ;
				}
			}

			Execution.OnUIThread ( 
				() => Log.Info( "TryClose requires a parent IConductor " + 
						"or a view with a Close method or IsOpen property." ) 
			);

        }
#endif

		/// <summary>
        ///		Invoked when this object is being removed from the application,
        ///		and will be subject to garbage collection .
        /// </summary>
        public void Dispose ()
        {
			// todo: unregister message handler(s) from Mediator .
            this.OnDisposed ();
        }

        /// <summary>
        ///		Child classes can override this method to 
		///		perform clean-up logic, such as removing event handlers.
        /// </summary>
        protected virtual void OnDisposed ()
        {
        }
    }
}
